// ------------------------------------------------------------------------------------------
// Licensed by Interprise Solutions.
// http://www.InterpriseSolutions.com
// For details on this license please visit  the product homepage at the URL above.
// THE ABOVE NOTICE MUST REMAIN INTACT.
// ------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using Interprise.Facade.Customer;
using Interprise.Facade.Base;

namespace InterpriseSuiteEcommerceCommon
{
    public class KitCartItem
    {
        public string ItemKitCode = string.Empty;
        public string CustomerCode = string.Empty;
        public string ItemCode = string.Empty;
        public string GroupCode = string.Empty;        

        public string UnitMeasureCode = string.Empty;
        public decimal UnitmeasureQuantity = decimal.Zero;

        public decimal Cost = decimal.Zero;
        public decimal CostRate = decimal.Zero;
        public decimal Price = decimal.Zero;
        public decimal PriceRate = decimal.Zero;

        public bool Match(KitCartItem other)
        {
            return  this.ItemKitCode.Equals(other.ItemKitCode) &&
                    this.CustomerCode.Equals(other.CustomerCode) &&
                    this.ItemCode.Equals(other.ItemCode) &&
                    this.GroupCode.Equals(other.GroupCode);
        }
    }

    public class KitComposition
    {
        private Guid _cartID = Guid.Empty;
        private List<KitCartItem> _compositions = new List<KitCartItem>();
        private Customer _thisCustomer = null;
        private string _itemKitCode = string.Empty;
        private string _pricingType = string.Empty;
        public string _unitMeasureCode = string.Empty;
        private decimal _quantity = decimal.One;

        private KitComposition(Customer forCustomer, string itemKitCode, Guid cartId)
        {
            this._thisCustomer = forCustomer;
            this._itemKitCode = itemKitCode;
            this._cartID = cartId;
        }

        public Guid CartID
        {
            get { return _cartID; }
            set { _cartID = value;; }
        }

        public string ItemKitCode
        {
            get{return _itemKitCode;}
        }

        public string PricingType
        {
            get { return _pricingType; }
            set { _pricingType = value; }
        }

        public List<KitCartItem> Compositions
        {
            get { return _compositions; }
        }

        public Customer ThisCustomer
        {
            get{return _thisCustomer;}
        }

        public string UnitMeasureCode
        {
            get { return _unitMeasureCode; }
            set { _unitMeasureCode = value; }
        }

        public decimal Quantity
        {
            get { return _quantity; }
            set { _quantity = value; }
        }

        public bool Matches(KitComposition other)
        {
            if (this.ItemKitCode != other.ItemKitCode || this.PricingType != other.PricingType) return false;
            if (this.Compositions.Count != other.Compositions.Count) return false;

            bool matchesAll = false;

            foreach (KitCartItem kitItem in Compositions)
            {
                matchesAll = (other.Compositions.Find(kitItem.Match) != null);

                if (!matchesAll)
                {
                    return false;
                }
            }

            return true;
        }

        public void AddToCart()
        {
            AppLogic.AddKitItem(CartID, ThisCustomer.CustomerCode, this.ItemKitCode, null, null, this.Compositions);
        }

        public void AddToGiftRegistry(Guid giftRegistryID, Guid registryItemCode)
        {
            AppLogic.AddKitItem(null, ThisCustomer.CustomerCode, this.ItemKitCode, giftRegistryID, registryItemCode, this.Compositions);
        }
        
        public decimal GetSalesPrice(ref decimal vat)
        {
            decimal salesPrice = decimal.Zero;

            decimal price = decimal.Zero;
            decimal priceRate = decimal.Zero;
            decimal cost = decimal.Zero;
            decimal costRate = decimal.Zero;

            vat = decimal.Zero;            

            foreach (KitCartItem kitItem in this.Compositions)
            {
                price += kitItem.Price;
                priceRate += kitItem.PriceRate;
            }

            salesPrice = priceRate;
            salesPrice *= this.Quantity;

            if (AppLogic.AppConfigBool("VAT.Enabled"))
            {
                // NOTE:
                //  In interprise, the kit details is defined to whatever is set on the Currency on the Selling Language
                //  If the current customer's currency is not                 
                bool isCustomerCurrencyIncludedForInventorySelling = InterpriseHelper.IsCurrencyIncludedForInventorySelling(ThisCustomer.CurrencyCode);

                // Special case 2 
                //  Currency is added in Inventory Selling Currency late
                //  after the kit has been created, ideally the kit should regenerate kit pricing for this currency
                //  but for the meantime, we should handle this by looking into the home currency
                bool currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem =
                InterpriseHelper.CurrencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYet(ThisCustomer.CurrencyCode, this.ItemKitCode);

                // if the currency is not included in the selling currencies for inventory
                // then get the rates for the Base currency -- The convert the exchange rate
                string lookupCurrency = string.Empty;
                // the current exchange rate if we should convert
                decimal exchangeRate = decimal.Zero;
                if (isCustomerCurrencyIncludedForInventorySelling &&
                    !currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem)
                {
                    lookupCurrency = ThisCustomer.CurrencyCode;
                }
                else
                {
                    lookupCurrency = Currency.GetHomeCurrency();
                    exchangeRate = Currency.GetExchangeRate(ThisCustomer.CurrencyCode);
                }

                //compute the cost
                string currencyCode = string.Empty;
                bool byTotalQuantity = false;
                decimal x_salesPrice = decimal.Zero;
                bool isSalesPriceInBasecurrency = false;
                decimal regularPrice = decimal.Zero;
                decimal promotionalPrice = decimal.Zero;
                string pricing = string.Empty;
                decimal percent = decimal.Zero;
                decimal discount = decimal.Zero;
                decimal categoryDiscount = decimal.Zero;
                string customerItemCode = string.Empty;
                string customerItemDescription = string.Empty;
                string inventoryItemDescription = string.Empty;
                decimal basePricingCost = decimal.Zero;
                decimal baseAverageCost = decimal.Zero;
                bool isInventorySpecialPriceExpired = false;
                bool isCustomerSpecialPriceExpired = false;

                foreach (KitCartItem kitItem in this.Compositions)
                {
                    BaseSalesOrderFacade.GetPrice(string.Empty,
                        ref currencyCode,
                        kitItem.ItemCode,
                        kitItem.UnitMeasureCode,
                        kitItem.UnitmeasureQuantity,
                        DateTime.Today,
                        decimal.Zero,
                        decimal.Zero,
                        Interprise.Framework.Base.Shared.Enum.DefaultPricing.None,
                        Interprise.Framework.Base.Shared.Enum.PricingMethod.None,
                        string.Empty,
                        ref byTotalQuantity,
                        ref x_salesPrice,
                        ref isSalesPriceInBasecurrency,
                        ref regularPrice,
                        ref promotionalPrice,
                        ref pricing,
                        ref percent,
                        ref discount,
                        ref categoryDiscount,
                        ref customerItemCode,
                        ref customerItemDescription,
                        ref inventoryItemDescription,
                        ref basePricingCost,
                        ref baseAverageCost,
                        ref isInventorySpecialPriceExpired,
                        ref isCustomerSpecialPriceExpired);

                    cost = baseAverageCost;
                    costRate = SimpleFacade.Instance.ConvertCurrency(exchangeRate, cost, false, ThisCustomer.CurrencyCode, Interprise.Framework.Base.Shared.Enum.CurrencyFormat.Total);
                }

                string customerCode = ThisCustomer.CustomerCode;

                if (ThisCustomer.IsNotRegistered)
                {
                    customerCode = ThisCustomer.AnonymousCustomerCode;
                }

                price *= this.Quantity;
                priceRate *= this.Quantity;
                cost *= this.Quantity;
                costRate *= this.Quantity;

                vat = ItemTaxFacade.CalculateTax(customerCode,
                        this.ItemKitCode,
                        this.UnitMeasureCode,
                        price,
                        priceRate,
                        cost,
                        costRate,
                        this.Quantity);

                if (ThisCustomer.VATSettingReconciled == VatDefaultSetting.Inclusive)
                {
                    salesPrice += vat;
                }
            }

            return salesPrice; 
        }

        public static KitComposition FromForm(Customer thisCustomer, CartTypeEnum cartType, string itemKitCode)
        {
            string kitContents = CommonLogic.FormCanBeDangerousContent("KitItems", false);
            return FromComposition(kitContents, thisCustomer, cartType, itemKitCode);
        }

        public static KitComposition FromForm(Customer thisCustomer, string itemKitCode)
        {
            string kitContents = CommonLogic.FormCanBeDangerousContent("KitItems", false);
            return FromComposition(kitContents, thisCustomer, CartTypeEnum.GiftRegistryCart, itemKitCode);
        }

        public static KitComposition FromComposition(string kitContents, Customer thisCustomer, CartTypeEnum cartType, string itemKitCode)
        {
            KitComposition composition = null;

            
            if (!string.IsNullOrEmpty(kitContents))
            {
                // NOTE:
                //  In interprise, the kit details is defined to whatever is set on the Currency on the Selling Language
                //  If the current customer's currency is not 
                bool isCustomerCurrencyIncludedForInventorySelling = InterpriseHelper.IsCurrencyIncludedForInventorySelling(thisCustomer.CurrencyCode);

                // Special case 2 
                //  Currency is added in Inventory Selling Currency late
                //  after the kit has been created, ideally the kit should regenerate kit pricing for this currency
                //  but for the meantime, we should handle this by looking into the home currency
                bool currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem =
                InterpriseHelper.CurrencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYet(thisCustomer.CurrencyCode, itemKitCode);

                // if the currency is not included in the selling currencies for inventory
                // then get the rates for the Base currency -- The convert the exchange rate
                string lookupCurrency = string.Empty;
                // the current exchange rate if we should convert
                decimal exchangeRate = decimal.Zero;
                if (isCustomerCurrencyIncludedForInventorySelling &&
                    !currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem)
                {
                    lookupCurrency = thisCustomer.CurrencyCode;
                }
                else
                {
                    lookupCurrency = Currency.GetHomeCurrency();
                    exchangeRate = Currency.GetExchangeRate(thisCustomer.CurrencyCode);
                }

                string[] selectedItems = kitContents.Split(',');
                composition = new KitComposition(thisCustomer, itemKitCode, Guid.Empty);

                if (selectedItems.Length > 0)
                {
                    using (SqlConnection con = new SqlConnection(DB.GetDBConn()))
                    {
                        con.Open();

                        using (SqlCommand cmdGetKitCodes = new SqlCommand("eCommerceGetKitCodes", con))
                        {
                            cmdGetKitCodes.CommandType = CommandType.StoredProcedure;

                            SqlParameter paramItemKitCode = new SqlParameter("@ItemKitcode", SqlDbType.NVarChar, 30);
                            SqlParameter paramKitItemCounter = new SqlParameter("@KitItemCounter", SqlDbType.Int);
                            SqlParameter paramKitGroupCounter = new SqlParameter("@KitGroupCounter", SqlDbType.Int);
                            SqlParameter paramCurrencyCode = new SqlParameter("@CurrencyCode", SqlDbType.NVarChar, 30);

                            cmdGetKitCodes.Parameters.Add(paramItemKitCode);
                            cmdGetKitCodes.Parameters.Add(paramKitItemCounter);
                            cmdGetKitCodes.Parameters.Add(paramKitGroupCounter);
                            cmdGetKitCodes.Parameters.Add(paramCurrencyCode);

                            paramItemKitCode.Value = itemKitCode;
                            paramCurrencyCode.Value = lookupCurrency;

                            foreach (string kitGroup in selectedItems)
                            {
                                string[] groups = kitGroup.Split(DomainConstants.KITCOMPOSITION_DELIMITER);
                                if (groups.Length != 2)
                                {
                                    // kit from form post composition is BROKEN..
                                    return null;
                                }

                                int kitGroupCounter, kitItemCounter;
                                if (int.TryParse(groups[0], out kitGroupCounter) && 
                                    int.TryParse(groups[1], out kitItemCounter))
                                {
                                    paramKitItemCounter.Value = kitItemCounter;
                                    paramKitGroupCounter.Value = kitGroupCounter;

                                    using (IDataReader reader = cmdGetKitCodes.ExecuteReader())
                                    {
                                        if (reader.Read())
                                        {
                                            KitCartItem selectedKitItem = new KitCartItem();
                                            selectedKitItem.CustomerCode = thisCustomer.CustomerCode;
                                            selectedKitItem.ItemKitCode = itemKitCode;

                                            selectedKitItem.ItemCode = DB.RSField(reader, "ItemCode");
                                            selectedKitItem.GroupCode = DB.RSField(reader, "GroupCode");

                                            // NOTE:
                                            // We don't need to cost price at this point
                                            // and it's an overhead to compute it
                                            // so we'll just fill it up later when we compute
                                            // the sales price, if we have tax (where needed)
                                            selectedKitItem.Cost = decimal.Zero;
                                            selectedKitItem.CostRate = decimal.Zero;

                                            selectedKitItem.UnitMeasureCode = DB.RSField(reader, "UnitMeasureCode");
                                            selectedKitItem.UnitmeasureQuantity = DB.RSFieldDecimal(reader, "UnitMeasureQuantity");

                                            selectedKitItem.Price = DB.RSFieldDecimal(reader, "Total");
                                            selectedKitItem.PriceRate = DB.RSFieldDecimal(reader, "TotalRate");

                                            if (isCustomerCurrencyIncludedForInventorySelling &&
                                                currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem)
                                            {
                                                selectedKitItem.PriceRate = Interprise.Facade.Base.SimpleFacade.Instance.ConvertCurrency(exchangeRate, selectedKitItem.Price, false, thisCustomer.CurrencyCode, Interprise.Framework.Base.Shared.Enum.CurrencyFormat.Total);
                                            }

                                            composition.Compositions.Add(selectedKitItem);
                                        }
                                        else
                                        {
                                            // kit item non-existent, kit composition is therefore BROKEN
                                            return null;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    // kit composition details are missing
                    return null;
                }
            }

            return composition;
        }

        public static KitComposition FromCart(Customer thisCustomer, CartTypeEnum cartType, string itemKitCode, Guid cartID)
        {
            // NOTE:
            //  In interprise, the kit details is defined to whatever is set on the Currency on the Selling Language
            //  If the current customer's currency is not 
            bool isCustomerCurrencyIncludedForInventorySelling = InterpriseHelper.IsCurrencyIncludedForInventorySelling(thisCustomer.CurrencyCode);

            // Special case 2 
            //  Currency is added in Inventory Selling Currency late
            //  after the kit has been created, ideally the kit should regenerate kit pricing for this currency
            //  but for the meantime, we should handle this by looking into the home currency
            bool currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem =
            InterpriseHelper.CurrencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYet(thisCustomer.CurrencyCode, itemKitCode);

            // if the currency is not included in the selling currencies for inventory
            // then get the rates for the Base currency -- The convert the exchange rate
            string lookupCurrency = string.Empty;
            // the current exchange rate if we should convert
            decimal exchangeRate = decimal.Zero;
            if (isCustomerCurrencyIncludedForInventorySelling &&
                !currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem)
            {
                lookupCurrency = thisCustomer.CurrencyCode;
            }
            else
            {
                lookupCurrency = Currency.GetHomeCurrency();
                exchangeRate = Currency.GetExchangeRate(thisCustomer.CurrencyCode);
            }

            KitComposition composition = new KitComposition(thisCustomer, itemKitCode, cartID);


            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "exec EcommerceGetKitCartComposition @CustomerCode = {0}, @CartID = {1}, @CartType = {2}, @CurrencyCode = {3}", DB.SQuote(thisCustomer.CustomerCode), DB.SQuote(cartID.ToString()), (int)cartType, DB.SQuote(lookupCurrency)))
                {
                    while (reader.Read())
                    {
                        KitCartItem kit = new KitCartItem();
                        kit.ItemKitCode = DB.RSField(reader, "ItemKitCode");
                        kit.ItemCode = DB.RSField(reader, "ItemCode");
                        kit.CustomerCode = DB.RSField(reader, "CustomerCode");
                        kit.GroupCode = DB.RSField(reader, "GroupCode");

                        // NOTE:
                        // We don't need to cost price at this point
                        // and it's an overhead to compute it
                        // so we'll just fill it up later when we compute
                        // the sales price, if we have tax (where needed)
                        kit.Cost = decimal.Zero;
                        kit.CostRate = decimal.Zero;

                        kit.UnitMeasureCode = DB.RSField(reader, "UnitMeasureCode");
                        kit.UnitmeasureQuantity = DB.RSFieldDecimal(reader, "UnitMeasureQuantity");

                        kit.Price = DB.RSFieldDecimal(reader, "Total");
                        kit.PriceRate = DB.RSFieldDecimal(reader, "TotalRate");

                        if (isCustomerCurrencyIncludedForInventorySelling &&
                            currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem)
                        {
                            kit.PriceRate = Interprise.Facade.Base.SimpleFacade.Instance.ConvertCurrency(exchangeRate, kit.Price, false, thisCustomer.CurrencyCode, Interprise.Framework.Base.Shared.Enum.CurrencyFormat.Total);
                        }

                        composition.PricingType = DB.RSField(reader, "KitPricingType");

                        composition.Compositions.Add(kit);
                    }
                }
            }

            return composition;
        }

        public static KitComposition FromSalesOrder(Customer thisCustomer, string salesOrderCode, string itemKitCode, int lineNum)
        {
            KitComposition composition = new KitComposition(thisCustomer, itemKitCode, Guid.Empty);


            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "exec eCommerceGetKitOrderComposition @SalesOrderCode = {0}, @LineNum = {1}", DB.SQuote(salesOrderCode), lineNum))
                {
                    while (reader.Read())
                    {
                        KitCartItem kit = new KitCartItem();
                        kit.ItemKitCode = DB.RSField(reader, "ItemKitCode");
                        kit.ItemCode = DB.RSField(reader, "ItemCode");
                        kit.CustomerCode = thisCustomer.CustomerCode;
                        kit.GroupCode = DB.RSField(reader, "GroupCode");

                        composition.PricingType = DB.RSField(reader, "KitPricingType");

                        composition.Compositions.Add(kit);
                    }
                }
            }

            return composition;
        }
       
    }
}












